#include "ws.packer.h"

#ifdef DEBUG
#include <iostream>
#endif

TOB::WS::Packer::Packer(std::string request, TOB::WS::Data* data, TOB::Nameserver::IP nsip, std::string username, std::string password) {
  
  // calc length
  unsigned int length = 0;
  length += sizeof(TOB::WS::Function::Type);
  length += request.length() + sizeof(unsigned int);
  length += username.length() + sizeof(unsigned int);
  length += password.length() + sizeof(unsigned int);
  length += sizeof(nsip) + sizeof(unsigned int);
  if (data != NULL) {
    length += data->getLength() + sizeof(unsigned int);
  }
  
  // test request
  TOB::WS::Request* req;
  try {
    req = new TOB::WS::Request(request);
  } catch (RequestException) {
    throw TOB::WS::PackerException(request);
    return;
  }
  
  // detect func
  TOB::WS::Function::Type func = req->getFunc();
  if (func == TOB::WS::Function::Unknown) {
    throw TOB::WS::PackerException(req->getScheme());
    return;
  }
  
  // filling
  unsigned int i = 0;
  char* buffer = new char[length];
  
  // push func
  *((TOB::WS::Function::Type*)(buffer + i)) = func;
  i += sizeof(TOB::WS::Function::Type);
  
  // push request
  *((unsigned int*)(buffer + i)) = request.length();
  i += sizeof(unsigned int);
  for (unsigned int j = 0; j < request.length(); ++j, ++i) {
    buffer[i] = request[j];
  }
  
  // push username
  *((unsigned int*)(buffer + i)) = username.length();
  i += sizeof(unsigned int);
  for (unsigned int j = 0; j < username.length(); ++j, ++i) {
    buffer[i] = username[j];
  }
  
  // push password
  *((unsigned int*)(buffer + i)) = password.length();
  i += sizeof(unsigned int);
  for (unsigned int j = 0; j < password.length(); ++j, ++i) {
    buffer[i] = password[j];
  }
  
  // push nsip
  *((unsigned int*)(buffer + i)) = sizeof(nsip);
  i += sizeof(unsigned int);
  *((TOB::Nameserver::IP*)(buffer + i)) = nsip;
  i += sizeof(nsip);
  
  // push data
  if (data != NULL) {
    *((unsigned int*)(buffer + i)) = data->getLength();
    i += sizeof(unsigned int);
    memcpy(buffer + i, data->getBuffer(), data->getLength());
  }
  
  // create packs
  unsigned int l = length;
  unsigned int j = 0;
  do {
    _packs.push_back(*(new package));
    _packs[j].length = (l >= PACKSIZE) ? PACKSIZE : l;
    memcpy(_packs[j].data, buffer + j * PACKSIZE, _packs[j].length);
    j++;
    l -= (l >= PACKSIZE) ? PACKSIZE : l;
   } while (l);
  
  if (req != NULL) {
    delete req;
  }
  delete[] buffer;
  
#ifdef DEBUG
  std::cout << "created packer: " << this << std::endl;
#endif
}

TOB::WS::Packer::Packer() {  
#ifdef DEBUG
  std::cout << "created packer: " << this << std::endl;
#endif
}

TOB::WS::Packer::~Packer() {
  while (_packs.size() > 0) {
    _packs.erase(_packs.begin());
  }  
#ifdef DEBUG
  std::cout << "deleted packer: " << this << std::endl;
#endif
}

int TOB::WS::Packer::getCount() {
  return _packs.size();
}

package& TOB::WS::Packer::operator [](int index) {
  return _packs[index];
}

void TOB::WS::Packer::push(package& p) {
  _packs.push_back(p);
}

void TOB::WS::Packer::erase(int index) {
  if (index < _packs.size()) {
    _packs.erase(_packs.begin() + index);
  }
}

TOB::WS::PackerException::PackerException(std::string scheme) {
  TOB::Log::error("WebServer::Packer: wrong scheme (scheme: " + scheme + ")");
}
